home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-04-26 | 11.4 KB | 319 lines | [TEXT/ZBAS] |
- 'FBSpinningGlobe.main by Robert Hommel
- '© Copyright 1994
- 'All rights granted for any use whatsoever
-
- 'This example program builds on the foundation of SWSimpleTest to
- 'create a more complex animation. It demonstrates the use of Sprites
- 'with multiple Frames, the use of multiple Layers to produce a
- 'three-dimensional appearance, and inactive (non-mobile) Sprites.
-
- 'You will notice a slight slowing of the animation as the Globe
- 'Sprites pass in front of or behind the SpriteWorld Text Sprite.
- 'FBSpriteWorld does rigorous checking to make sure that only those
- 'Sprites that have moved or changed frames are drawn. Most of the
- 'time, the Text Sprite does not need to be drawn; however, whenever
- 'a Globe intersects the Text, FBSpriteWorld must render at least a
- 'part of the Text Sprite, and this causes the animation to slow down.
- 'This slowing is only noticeable because most of the Globe Sprites
- 'are moved 'as quickly as possible.' If this were anything other
- 'than a demo, we would assign move times to each Globe Sprite suf-
- 'ficient to keep them moving at a steady pace.
-
- 'We can learn several lessons from the 'slowing' phenomenon: namely,
- 'keep the number of Sprites to a minimum, keep the number of moving
- 'Sprites as small as possible, avoid intersecting inactive Sprites,
- 'and for optimum performance, keep the Sprites small. If you must
- 'have large Sprites, try to make them wide rather than tall.
-
- 'When you click the mouse button to exit this program, an Alert will
- 'display showing the number of animation frames performed per second.
- 'On my original Mac LC, I get about 14.5 frames per second. The
- 'C version of SpriteWorld by Tony Myles clocks a cool 22 frames per
- 'second using CopyBits, and 30+ with an assembly bit blitter! Such
- 'figures indicate we've got a long way to go with improving the
- 'animation engine - any ideas out there?
-
- 'Disclaimer: I've tested these routines quite thoroughly on my Mac
- 'LC running System 7.01 and FB 1.02c. I make no promises or warranties
- 'of any kind.
- '*********************************************************************
-
- COMPILE 0, _MacsBugLabels _caseInsensitive
- RESOURCES "FBSpriteWorld.RSRC"
-
- '---------------------------- GLOBALS --------------------------------
-
- GLOBALS "GraphicUtils.glbl"
- GLOBALS "FBSpriteWorld.glbl"
-
- _backPatRSRC=129
- _spriteGlobeRSRC=132
- _spriteTextRSRC=228
-
- END GLOBALS
-
- GOTO "Main"
-
- '--------------------------- INCLUDES --------------------------------
-
- INCLUDE "FBSpriteWorld.incl"
-
- '------------------------- ERROR HANDLER -----------------------------
-
- CLEAR LOCAL
- LOCAL FN FatalError(errCode)
- 'Simple error handler. You'll want to improve on this in your
- 'program...
-
- LONG IF errCode<>_noErr
- SELECT errCode
- CASE _swTooManyLayers:errStr$="Out of Memory."
- CASE _swTooManySprites:errStr$="Too many Sprites."
- CASE _swTooManyFrames:errStr$="Too many Frames."
- CASE _swNotSystemSeven:errStr$="SpriteWorld requires System 7!"
- CASE _swTimeMgrNotPresent:errStr$="SpriteWorld requires Time Manager."
- CASE _swOutOfMemory:errStr$="Out of Memory."
- CASE ELSE
- errStr$="Unknown error."
- END SELECT
-
- tmp$="Error Code:"+STR$(errCode)
- CALL PARAMTEXT(errStr$,tmp$,"","")
- x=FN STOPALERT(1,0)
- END
- END IF
- END FN
-
- '------------------------ SPRITEWORLD PROCS --------------------------
-
- "SWBounceMoveProc"
- ENTERPROC(SWPtr&,spritePtr&,curRectPtr&)
- 'standard bounce movement proc. Keeps sprite inside sprite boundsRect
-
- LONG IF curRectPtr&.left%+spritePtr&.xDelta%<=spritePtr&.sBoundsRect.left%
- spritePtr&.xDelta%=spritePtr&.xDelta%*-1
- XELSE
- LONG IF curRectPtr&.right%+spritePtr&.xDelta%>=spritePtr&.sBoundsRect.right%
- spritePtr&.xDelta%=spritePtr&.xDelta%*-1
- END IF
- END IF
- LONG IF curRectPtr&.top%+spritePtr&.yDelta%<=spritePtr&.sBoundsRect.top%
- spritePtr&.yDelta%=spritePtr&.yDelta%*-1
- XELSE
- LONG IF curRectPtr&.bottom%+spritePtr&.yDelta%>=spritePtr&.sBoundsRect.bottom%
- spritePtr&.yDelta%=spritePtr&.yDelta%*-1
- END IF
- END IF
- EXITPROC
- RETURN
-
- "SWTimeTask"
- 'Sets the frameTTHasFired or moveTTHasFired field of the sprite record
- 'to _zTrue (-1). Called by the Time Manager if frameTimeInterval or
- 'moveTimeInterval field of sprite record > 0.
-
- ` move.w #-1,tmXQSize(a1) ;[move|frame]TTHasFired=_zTrue
- ` rts ;return
-
- '-------------------------- MAIN LOOP --------------------------------
-
- "Main"
- DIM wRect.8,curRect.8
- DIM mySW.SpriteWorldRec
- DIM myLayer.SWLayerRec(1)
- DIM textLayer.SWLayerRec
- DIM mySprite.SWSpriteRec(3)
- DIM textSprite.SWSpriteRec
- DIM myFrame.SWFrameRec(9)
- DIM textFrame.SWFrameRec
- DIM wndPort&
-
- CURSOR _watchCursor 'takes a few seconds to set up
-
- '--------------------------------------------------------------------
- 'Initialization and Set Up
- '--------------------------------------------------------------------
-
- 'Can we run in this environment?
- err=FN SWEnterSpriteWorld
- FN FatalError(err)
-
- 'Open a window and draw pretty background
- pat&=FN GETPIXPAT(_backPatRSRC) 'get pattern RSRC
- wWidth=SYSTEM(_scrnWidth) 'screen width
- wHeight=SYSTEM(_scrnHeight) 'screen height
- CALL SETRECT(wRect,0,40,wWidth,wHeight) 'set window Rect
- 'CALL SETRECT (wRect, 1050,30,1700,400)
- WINDOW #1,"Spinning Globe",@wRect,5 'open a window the same size as wRect
- wndPort&=FN GetCurrPort 'get grafPtr
- CALL FILLCRECT(#wndPort&+_portRect,pat&) 'fill with nice pattern
-
- '// NOTE: At this point, it would be easier to create the //
- '// SpriteWorld based on the window port by using //
- '// SWCreateSWFromWindow, as we have in the other examples. //
- '// However, here we'll create the SpriteWorld from 'scratch' //
- '// with our own background PICT and bounding rectangle. This //
- '// is the technique you would use to create a SpriteWorld with //
- '// a bounding rectangle smaller than the window's PortRect, or //
- '// to use a background different than the current background //
- '// of the window. //
-
- pict&=USR GETPICT(#wndPort&+_portRect) 'take pict of screen
-
- 'Create SpriteWorld
- err=FN SWCreateSpriteWorld(@mySW,wndPort&,wndPort&+_portRect,pict&)
- FN FatalError(err)
-
- 'get time task ptr (same for all sprites)
- ttPtr&=LINE "SWTimeTask"
-
- '--------------------------------------------------------------------
- 'Create Globe Sprites
- '--------------------------------------------------------------------
-
- 'get moveProc ptr (same for all sprites)
- movePtr&=LINE "SWBounceMoveProc"
-
- 'create first globe sprite
- err=FN SWSpriteFromPict(@mySprite(0),0,0,0,wndPort&+_portRect,_zTrue,2,2,-1,ttPtr&,movePtr&,_spriteGlobeRSRC)
- FN FatalError(err)
-
- 'add frames to globe sprite (add frames before clonning!)
- FOR x=0 TO 9
- err=FN SWFrameFromPict(@myFrame(x),_spriteGlobeRSRC+(x*3))
- FN FatalError(err)
- err=FN SWAddFrameToSprite(@mySprite(0),@myFrame(x))
- FN FatalError(err)
- NEXT
-
- 'clone sprite(0) to make sprites 1-3
- FOR x=1 TO 3
- FN SWCloneSprite(@mySprite(0),@mySprite(x),ttPtr&)
- NEXT
-
- 'set sprite locations for sprites 1-3
- FN SWSetSpriteLocation(@mySprite(1),465,0)
- FN SWSetSpriteLocation(@mySprite(2),465,290)
- FN SWSetSpriteLocation(@mySprite(3),0,290)
-
- 'change sprite frame advance for sprites 1 and 3
- FN SWSetSpriteFrameAdv(@mySprite(1),1)
- FN SWSetSpriteFrameAdv(@mySprite(3),1)
-
- 'change sprite move delta for sprites 0 and 2
- FN SWSetMoveDelta(@mySprite(0),1,1)
- FN SWSetMoveDelta(@mySprite(2),6,6)
-
- 'set sprite move time for sprite 0 (all others will move as fast as they can)
- FN SWSetMoveTime(@mySprite(0),500)
- 'set sprite frame time for sprite 1 (all others will advance frames as fast as they can)
- FN SWSetFrameTime(@mySprite(1),150)
-
- '--------------------------------------------------------------------
- 'Create Text Sprite
- '--------------------------------------------------------------------
-
- '// NOTE: Normally, we use SWSpriteFromPict to create a sprite //
- '// that is based on a PICT resource, like our text sprite. For //
- '// purposes of demonstration, we'll create this sprite from //
- '// 'scratch,' by calling SWInitSprite instead. We'll extract //
- '// frameRect from the PICT resource, move it where we want it, //
- '// then pass it to the initialization routine. SWInitSprite //
- '// would be most useful if you were making a sprite from some- //
- '// thing other than a PICT resource, such as an object drawn on //
- '// the screen. //
-
- 'create frame first so we can easily get its rect
- err=FN SWFrameFromPict(@textFrame,_spriteTextRSRC)
- FN FatalError(err)
-
- 'get frame rect
- BLOCKMOVE @textFrame+_fBoundsRect,@curRect,8
-
- 'center it in window rect
- FN CenterRect(curRect,wndPort&.portRect&)
-
- 'create text sprite
- FN SWInitSprite(@textSprite,0,@curRect,wndPort&+_portRect,_zTrue,0,0,0,ttPtr&,movePtr&)
-
- 'set move and frame times to -1 (no frame advance or movement)
- FN SWSetMoveTime(@textSprite,-1)
- FN SWSetFrameTime(@textSprite,-1)
-
- 'add frame to text sprite
- err=FN SWAddFrameToSprite(@textSprite,@textFrame)
- FN FatalError(err)
-
- '---------------------------------------------------------------------
- 'Assemble the Pieces
- '---------------------------------------------------------------------
-
- 'add globe sprites to globe layer 0
- err=FN SWAddSpriteToLayer(@myLayer(0),@mySprite(0))
- FN FatalError(err)
- err=FN SWAddSpriteToLayer(@myLayer(0),@mySprite(1))
- FN FatalError(err)
-
- 'add text sprite to text layer
- err=FN SWAddSpriteToLayer(@textLayer,@textSprite)
- FN FatalError(err)
-
- 'add globe sprites to globe layer 1
- err=FN SWAddSpriteToLayer(@myLayer(1),@mySprite(2))
- FN FatalError(err)
- err=FN SWAddSpriteToLayer(@myLayer(1),@mySprite(3))
- FN FatalError(err)
-
- 'add layers to world
- err=FN SWAddLayerToWorld(@mySW,@myLayer(0))
- FN FatalError(err)
- err=FN SWAddLayerToWorld(@mySW,@textLayer)
- FN FatalError(err)
- err=FN SWAddLayerToWorld(@mySW,@myLayer(1))
- FN FatalError(err)
-
- '---------------------------------------------------------------------
- 'Final Set Up
- '---------------------------------------------------------------------
-
- 'Prepare loadframe for animation
- FN SWRefreshBackground(@mySW)
-
- CURSOR _arrowCursor 'we're ready to go...
-
- 'Render 1st frame of animation
- FN SWAnimateSpriteWorld(@mySW)
-
- '---------------------------------------------------------------------
- 'Animation Loop
- '---------------------------------------------------------------------
-
- a&=TIMER:frames&=0 'set initial timer vars
- DO
- FN SWProcessSpriteWorld(@mySW) 'move sprites
- FN SWAnimateSpriteWorld(@mySW) 'render sprites
- CALL SYSTEMTASK 'be kind to system
- INC(frames&) 'keep track of animation frames
- UNTIL FN BUTTON
-
- '---------------------------------------------------------------------
- 'Report Animation Speed
- '---------------------------------------------------------------------
-
- 'How'd we do?
- elapsedTime&=TIMER-a&
- a$=STR$(frames&)+" frames drawn in"+STR$(elapsedTime&)+" secs."
- b$="Average: "+LEFT$(STR$(frames&\elapsedTime&),6)+" frames per second."
- CALL PARAMTEXT(a$,b$,"","")
- x=FN NOTEALERT(1,0)
-
- '---------------------------------------------------------------------
- 'Dispose SpriteWorld and Exit
- '---------------------------------------------------------------------
-
- err=FN SWDisposSpriteWorld(@mySW)
- FN FatalError(err)
-
- END
-
-